package com.idanchuang.component.businesslog.es.index;

import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NByteArrayEntity;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.StringJoiner;

/**
 * The EndpointBuilder
 *
 * @since 2020/7/17
 */
public class IndexManageRequest {

    static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
        return createEntity(toXContent, xContentType, ToXContent.EMPTY_PARAMS);
    }

    static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType, ToXContent.Params toXContentParams)
            throws IOException {
        BytesRef source = XContentHelper.toXContent(toXContent, xContentType, toXContentParams, false).toBytesRef();
        return new NByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
    }

    /**
     * Returns a {@link ContentType} from a given {@link XContentType}.
     *
     * @param xContentType the {@link XContentType}
     * @return the {@link ContentType}
     */
    @SuppressForbidden(reason = "Only allowed place to convert a XContentType to a ContentType")
    public static ContentType createContentType(final XContentType xContentType) {
        return ContentType.create(xContentType.mediaTypeWithoutParameters(), (Charset) null);
    }

    private final StringJoiner joiner = new StringJoiner("/", "/", "");

    public IndexManageRequest addPathPart(String... parts) {
        for (String part : parts) {
            if (Strings.hasLength(part)) {
                joiner.add(encodePart(part));
            }
        }
        return this;
    }

    public IndexManageRequest addCommaSeparatedPathParts(String[] parts) {
        addPathPart(String.join(",", parts));
        return this;
    }

    public IndexManageRequest addCommaSeparatedPathParts(List<String> parts) {
        addPathPart(String.join(",", parts));
        return this;
    }

    public IndexManageRequest addPathPartAsIs(String... parts) {
        for (String part : parts) {
            if (Strings.hasLength(part)) {
                joiner.add(part);
            }
        }
        return this;
    }

    public String build() {
        return joiner.toString();
    }

    private static String encodePart(String pathPart) {
        try {
            //encode each part (e.g. index, type and id) separately before merging them into the path
            //we prepend "/" to the path part to make this path absolute, otherwise there can be issues with
            //paths that start with `-` or contain `:`
            //the authority must be an empty string and not null, else paths that being with slashes could have them
            //misinterpreted as part of the authority.
            URI uri = new URI(null, "", "/" + pathPart, null, null);
            //manually encode any slash that each part may contain
            return uri.getRawPath().substring(1).replaceAll("/", "%2F");
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("Path part [" + pathPart + "] couldn't be encoded", e);
        }
    }
}
